package com.AdvancedDemos.多态;

public class instanceofDemo {
    public static void main(String[] args) {
        //为了避免出现类型转换错误,可以使用 关键字instanceof 来判断某个父类/接口变量实际指向的对象的类型,从而知道是否可以沿着继承/实现关系向下强转成某个子类/实现类类型,来调用某个子类/实现类中特有的方法

        /**
         * 格式:
         * 指向子类/实现类实例的父类/接口变量a instanceof 子类/实现类A
         如果a变量指向的实际是A类型(或A类的子类型/A接口的实现类)的实例,那么返回true,否则返回false
         */

        /**
         * if(父类/接口变量a instanceof 子类/实现类A){//
         *      ((A)a).子类/实现类中特有的某个方法();
         *      //父类/接口变量a实际指向的是子类/实现类A的实例,通过父类/接口变量向下强转成子类/实现类变量从而可以调用子类/实现类中特有的方法
         * }
         * */

        //此外,由于instanceof可以判断是否是指定父类/接口的子类型的实例,因此可以
        Fu[] f = new Fu[2];
        f[0] = new Zi1();
        f[1] = new Zi2();
        for (int i = 0; i < f.length; i++) {
            if (f[i] instanceof JieKou) {//如果f[i]实际指向的是JieKou接口或者其实现类
                ((JieKou) f[i]).接口中的抽象方法();//这里将父类型变量直接转成了子类实现的接口类型的变量,然后调用接口中的方法,实际执行的是实现类(子类型)中重写的接口中的方法
            }
        }
        /**
         * 之所以可以这样转换,是因为java中允许子类/实现类对象在赋值等操作中自动实现向上类型转换;
         * 这也是为什么可以直接new一个子类对象却使用父类变量来接而且还不需要强制类型转换,因为已经自动变成了父类类型;
         * 但是当父类变量要调用子类中特有的方法时,就必须显式得强制类型转换了,因为可能是不安全的,子类对象中极有可能存在父类对象中不存在的变量方法,只有在明确被转换对象实际类型的时候,才可以强制类型转换,这也是为什么要先使用instanceof关键字判断的原因;
         * 在上述案例中,不管是Zi1类还是Zi2类的对象,都是使用其父类Fu类变量来指向的,然后在if()判断中,询问Fu类变量fu指向的对象是否是JieKou接口实现类或其子类的实例,如果是,那表明该对象一定实现了JieKou接口,一定重写了其中的抽象方法,于是直接通过显式的强制类型转换将Fu类变量转成其子类(Zi1 Zi2 ...)实现的JieKou接口类型,对子类而言是向上转换,接口中的方法,子类都有,子类有的,接口可能没有,接口变量不可能调到实现类中特有的函数,所以是安全的,不管是Fu类变量还是JieKou接口变量都是可以指向子类Zi1 Zi2实例的,原来Fu类变量是看不到接口中的抽象方法()的,强转过后成了接口类型的变量,就可以调用接口中的抽象方法()了,而实际其指向的是子类(实现类)的对象,其一定重写了接口中的抽象方法(),实际调用的是子类(实现类)中重写后的接口中的抽象方法()
         */
    }
}

interface JieKou {
    void 接口中的抽象方法();
}

class Fu {

}

class Zi1 extends Fu implements JieKou {

    @Override
    public void 接口中的抽象方法() {
        System.out.println("Zi1");
    }
}

class Zi2 extends Fu implements JieKou {

    @Override
    public void 接口中的抽象方法() {
        System.out.println("Zi2");
    }
}




